#include "network.h"

phatIP::phatIP()
{
	mServer0 = INVALID_SOCKET;
	mClient0 = INVALID_SOCKET;
	ZeroMemory( &mAddr0, sizeof( mAddr0) );
	if (WSAStartup( 2.0, &wsaData)==0)
	{
		if (LOBYTE(wsaData.wVersion) < 2)	// Check if major version is at least iReqWinsockVer
			throwError("Version of winsock not 2.0 compatible");
	}
	else
		throwError("Starting winsock failed.");
}

phatIP::~phatIP()
{
	closeServer();

	// Cleanup winsock
	if(WSACleanup()!=0)
		throwError("Closing winsock failed.");
}

void phatIP::openServer()
{
	mAddr0.sin_family = AF_INET;
	mAddr0.sin_port = htons(default_port);
	mAddr0.sin_addr.S_un.S_addr =  INADDR_ANY; // use default

	if(mServer0 == INVALID_SOCKET)
		mServer0 = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	else
		throwError("Creating mServer0 when its already open");

	if(mServer0 == INVALID_SOCKET)
		throwError("Couldn't create mServer0");

	if(mClient0 == INVALID_SOCKET) // must be null
		mClient0 = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	else
		throwError("Creating mServer0 when its already open");

	if(mClient0 == INVALID_SOCKET)
		throwError("Couldn't create mClient0");

	// Bind socket to port 80 from any address
	if ( bind(mServer0, (sockaddr*)(&mAddr0), sizeof(mAddr0)) == SOCKET_ERROR )
	{
		throwError("Couldn't bind mServer0");
		closeSocket(mServer0);
	}

	gInt = WSAAsyncSelect(mServer0, gWindow, WM_SOCKET, server_flags );
	if( gInt != 0)
		throwError("Couldn't async mServer0");

	gInt = WSAAsyncSelect(mClient0, gWindow, WM_SOCKET, client_flags );
	if( gInt != 0)
		throwError("Couldn't async mClient0");


	// Listen to two clients
	if ( listen(mServer0, 2) !=0 )
	{
		throwError("could not put socket in listening mode.");
		closeSocket(mServer0);
	}

}

void phatIP::closeServer()
{
	closeSocket( mClient0 );
	closeSocket( mServer0 );
}

// Default to default port and non-blocking mode async
void phatIP::connectSocket(SOCKET &sSocket, USHORT uPort, UINT iMode, UINT iFlags )
{
	sockaddr_in clientAddr;

	clientAddr.sin_family = AF_INET;
	clientAddr.sin_port = htons(uPort);
	clientAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");

	//// Setup async
	if( sSocket == INVALID_SOCKET )
	gInt = WSAAsyncSelect(sSocket, gWindow, WM_SOCKET, iFlags );
	if( gInt != 0 )
	{
		gInt = WSAGetLastError();
		throwError("Couldn't set async");
	}

	if( sSocket != INVALID_SOCKET )
	{
		// Connect to the server
		gInt = connect( sSocket, (sockaddr*)(&clientAddr), sizeof(clientAddr) );
		if( gInt != 0 )
		{
			gInt = WSAGetLastError();
			if( gInt == WSAEISCONN )
				throwError("already connected.");
			else if( gInt == WSAEWOULDBLOCK )
				connectSocket( sSocket );
			else
				throwError("couldn't connectSocket mServer0");
		}

	}
	else // create socket and try again once
	{
		if( gInt != 5001 )
			gInt = 5000;
		if( gInt == 5000 )
			sSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

		if( sSocket == INVALID_SOCKET )
			throwError("Couldn't create socket");
		else
		{
			gInt = 5001;
			connectSocket( sSocket );
		}
	}
}

void phatIP::closeSocket(SOCKET &sSocket)
{
	if( sSocket != INVALID_SOCKET )
	{
		shutdown(sSocket, SD_BOTH);
		closesocket(sSocket);
		sSocket = INVALID_SOCKET;
	}
	else
		throwError("Trying to close a already closed socket");
}

void phatIP::acceptConn( SOCKET &sSocket )
{
	sockaddr_in clientAddr;
	int         clientSockSize = sizeof(clientAddr);

	//clientAddr.sin_family = AF_INET;
	//clientAddr.sin_port = htons(default_port);
	//clientAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");

	if(mServer0 != INVALID_SOCKET && sSocket != mServer0)
	{
		while(sSocket!=INVALID_SOCKET&&sSocket!=SOCKET_ERROR)
		{
			throwError("Waiting for connections");

			sSocket = accept( mServer0 , (struct sockaddr *)&clientAddr, &clientSockSize);
			if( sSocket != INVALID_SOCKET )
			{
				break;
			}
			else
			{
				gInt = WSAGetLastError();

				sSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

				if(sSocket == INVALID_SOCKET)
					throwError("Couldn't create sSocket");

				gInt = WSAAsyncSelect(sSocket, gWindow, WM_SOCKET, (FD_CLOSE|FD_READ) );
				if( gInt != 0)
					throwError("Couldn't async sSocket");

				/* // non blocking by default
				gInt = ::ioctlsocket(sSocket, FIONBIO, (unsigned long *) 1);
				if( gInt == SOCKET_ERROR )
				throwError("Couldn't set blocking on sSocket in acceptConn()");*/

				sSocket = accept(mServer0, (struct sockaddr *)(&clientAddr),
					&clientSockSize);
				if( sSocket != INVALID_SOCKET )
					return;
					break;
			}
		}


		if (sSocket == INVALID_SOCKET)
		{

			if( sSocket== INVALID_SOCKET) // must be null
				sSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
			else
				throwError("Creating sSocket when its already open");

			if(sSocket == INVALID_SOCKET)
				throwError("Couldn't create sSocket");

			gInt = WSAAsyncSelect(sSocket, gWindow, WM_SOCKET, client_ro_flags );
			if( gInt != 0)
				throwError("Couldn't async sSocket");

			acceptConn( sSocket );
		}
		else
		{
			if( send( sSocket, "Welcome to the server.", 24, 0) == SOCKET_ERROR )
				throwError("Send failed after accept.");
			// Push into client vector
		}
	}
}


void Send( SOCKET &sSocket, string sBuffer, int iSize )
{
	if( send(sSocket, sBuffer.c_str(), iSize, 0 ) == SOCKET_ERROR )
	{
		gInt = WSAGetLastError();
		throwError("socket error while sending.");
	}
}

///////////////////////////////////////////////////////////////////////////////
// Encryption stuff
///////////////////////////////////////////////////////////////////////////////
void rot13(char *pBuffer, int size)		//http://en.wikipedia.org/wiki/ROT13
{
	for(int i=0;i<size;i++)
	{
		char c = pBuffer[i];
		if ((c >= 'a' && c < 'n') || (c >= 'A' && c < 'N') )
			c += 13;
		else if ((c>='n' && c <= 'z') || (c>='N' && c <= 'Z'))
			c -= 13;
		else
			continue;
		pBuffer[i] = c;
	}
}